/*
 * Layer.cpp
 *
 *  Created on: 2010-10-25
 *      Author: wenjian
 */

#include "Layer.h"
#include "../draw/AbstractDrawPage.h"
#include "DrawPage.h"
#include "Selection.h"
#include "Element.h"
#include "Elements.h"

namespace Ed {

  Layer::Layer(AbstractDrawPage* page, Selection* selct):
      AbstractLayer(page, selct),
    clipedRegion(NULL), background(0,0,0,0) {
    if(!selct){
      defaultSelection = new Selection();
      defaultSelection->setLayer(this);
      selection = defaultSelection;
    }else{
      selct->setLayer(this);
    }
  }

  Layer::~Layer()  {
    if(defaultSelection){delete defaultSelection;}
    destroyDoubleBuffer();
    destroyDrawRegion();
  }
  void Layer::setBackground(const Gdiplus::Color& c){
      background = c;
  }

  /**
   * 返回背景
   */
  const Gdiplus::Color& Layer::getBackground(){
    return background;
  }

  vector<Element*>* Layer::getIntersectionElements(vector<Element*>* v, const vector<const Gdiplus::RectF*>* rects, const vector<Element*>* excludeds, const vector<Element*>* appendeds){
    const vector<Element*>* els = getElements();
    ConstIterator it = els->begin();
    for(;it!=els->end(); it++){
      Element* e = *it;
      if(excludeds!=NULL && binary_search(excludeds->begin(), excludeds->end(), e)){
        continue;
      }
      if((appendeds!=NULL && binary_search(appendeds->begin(), appendeds->end(), e))
        || e->intersects(rects)){
        v->push_back(e);
      }
    }
    return v;
  }

  vector<Element*>* Layer::getIntersectionElements(vector<Element*>* v, const Gdiplus::RectF* r, const vector<Element*>* excludeds, const vector<Element*>* appendeds){
    const vector<Element*>* els = getElements();
    ConstIterator it = els->begin();
    for(;it!=els->end(); it++){
      Element* e = *it;
      if(excludeds!=NULL && binary_search(excludeds->begin(), excludeds->end(), e)){
        continue;
      }
      if((appendeds!=NULL && binary_search(appendeds->begin(), appendeds->end(), e))
        || e->intersects(r)){
        v->push_back(e);
      }
    }
    return v;
  }

  //virtual vector<Element*>* getIntersectionElements(vector<Element*>* v,  const vector<Element*>* els, const vector<Element*>* excludeds=NULL, const vector<Element*>* appendeds=NULL);
  vector<Element*>* Layer::getIntersectionElements(vector<Element*>* v, const vector<Element*>* intersEls, const vector<Element*>* excludeds, const vector<Element*>* appendeds){
    const vector<Element*>* els = getElements();
    ConstIterator it = els->begin();
    for(;it!=els->end(); it++){
      Element* e = *it;
      if(excludeds!=NULL && binary_search(excludeds->begin(), excludeds->end(), e)){
        continue;
      }
      if((appendeds!=NULL && binary_search(appendeds->begin(), appendeds->end(), e))
        || e->intersects(intersEls)){
        v->push_back(e);
      }
    }
    return v;
  }

  vector<Element*>* Layer::getIntersectionElements(vector<Element*>* v, Element* el, const vector<Element*>* excludeds, const vector<Element*>* appendeds){
    const vector<Element*>* els = getElements();
    ConstIterator it = els->begin();
    for(;it!=els->end(); it++){
      Element* e = *it;
      if(excludeds!=NULL && binary_search(excludeds->begin(), excludeds->end(), e)){
        continue;
      }
      if((appendeds!=NULL && binary_search(appendeds->begin(), appendeds->end(), e))
        || e->intersects(el)){
        v->push_back(e);
      }
    }
    return v;
  }


  /**
   * 创建双缓冲
   */
  void Layer::createDoubleBuffer(){
//    if(!graphics){
//      // 创建缓冲
//      bufferBmp = new Gdiplus::Bitmap((int)width(), (int)height());
//
//      HDC hostDC = ((DrawPage*)getDrawPage())->getPageHDC();
//      bufferDC = CreateCompatibleDC(hostDC);
//      HBITMAP bmp = CreateCompatibleBitmap( hostDC, (int)width(), (int)height());
//      SelectObject( bufferDC, bmp );
//      DeleteObject( bmp );
//
//      maskDC = CreateCompatibleDC(hostDC);
//      //maskBmp = CreateCompatibleBitmap( hostDC, (int)width(), (int)height());
//      maskBmp = CreateBitmap((int)width(), (int)height(), 1, 1, NULL); // 建立单色位图
//      SelectObject( bufferDC, bmp );
//      SetBkColor(maskDC, 0);
//
//      //生成 GDI+ Graphics
//      graphics = new Gdiplus::Graphics(bufferBmp);
//      //graphics = new Gdiplus::Graphics(bufferDC);
//      graphics->SetPageUnit(Gdiplus::UnitPixel);
//      graphics->SetSmoothingMode(Gdiplus::SmoothingModeHighQuality);
//      graphics->SetTextRenderingHint(Gdiplus::TextRenderingHintClearTypeGridFit);
//      //SetBkColor(bufferDC, 0 );
//      graphics->Clear(background);
//    }
  }

  /**
   * 销毁双缓冲
   */
  void Layer::destroyDoubleBuffer(){
//    if(graphics){
//      delete graphics;
//      graphics = NULL;
//    }
//    if(bufferBmp){
//      delete bufferBmp;
//      bufferBmp = NULL;
//    }
//    if(bufferCachedBmp){
//      delete bufferCachedBmp;
//      bufferCachedBmp = NULL;
//    }
//    if(bufferDC){
//      ReleaseDC(NULL, bufferDC);
//      bufferDC = NULL;
//    }
//    if(maskDC){
//      ReleaseDC(NULL, maskDC);
//      maskDC = NULL;
//    }
//    if(maskBmp){
//      DeleteObject( maskBmp );
//      maskBmp = NULL;
//    }
  }



  void Layer::draw(Gdiplus::Graphics* g) {
    if(!isVisible() || !isModified()){
      return;
    }
//    long stime = clock();

    if(drawMode==DrawMode_All || isRedrawAll()){
      //绘制所有
      drawAll(g);
    }else{
      //区域绘制
      drawRegion(g);
    }
    //清除层被修改状态
    setModified(false);

//    cout<<"draw one layer("<< this <<") (copy Image) use time:"<<(clock()-stime)<<endl;
  }


  void Layer::drawRegion(Gdiplus::Graphics* g){
    drawedCount = 0;
    long stime = clock();

    //过滤出需要重绘的元素
    Elements modifiedElements;
    Elements redrawedElements;
    const vector<Element*>* els = getElements();
    ConstIterator it = els->begin();
    for(;it!=els->end(); it++){
      Element* e = *it;
      if(!e->isVisible()){
        continue;
      }
      if(e->isModified()){
        if(enableDisplay(e)){
          modifiedElements.add(e);
          unionDrawRegion(e->getBoundRect());
        }
      }else if(e->isRedraw()){
        if(enableDisplay(e)){
          redrawedElements.add(e);
        }else{
          //如果不在显示区域，就设置修改标记
          e->setModified(true);
        }
      }
    }

//    cout<<"redrawedElements.size() is "<<redrawedElements.size()<<endl;
//    cout<<"modifiedElements.size() is "<<modifiedElements.size()<<endl;
//    cout<<"clipedRegion is "<<clipedRegion<<endl;
    if(clipedRegion){
      //剪掉需要重绘的区域
      clipDrawRegion(g);

      const vector<Element*>* redrawedEls = (const vector<Element*>*)redrawedElements.getElements();
      if(modifiedElements.empty()){
        //绘制仅重画自己的元素
        for(ConstIterator it = redrawedEls->begin(); it != redrawedEls->end(); it++){
          (*it)->draw(g);
          drawedCount++;
        }
      }else if(!modifiedElements.empty()){
        //两者都重画
        vector<Element*> allRedrawedEls;
        redrawedElements.addAll(modifiedElements.getAbstractElements());
        redrawedElements.sort();
        //getIntersectionElements(&allRedrawedEls, modifiedElements.getBoundRects(), NULL, redrawedElements.getElements());
        getIntersectionElements(&allRedrawedEls, (const vector<Element*>*)modifiedElements.getElements(), NULL, (const vector<Element*>*)redrawedElements.getElements());
        for(Iterator it = allRedrawedEls.begin(); it!=allRedrawedEls.end(); it++){
          if((*it)->isVisible() && enableDisplay(*it)){
            drawElement(*it, g);
//            (*it)->draw(g);
//            (*it)->setModified(false);
//            (*it)->setRedraw(false);
            drawedCount++;
          }
        }
      }

//      //更新画布宽度和高度
//      allElements.destroyBounds();
//      const Gdiplus::RectF* rectF = allElements.getBoundRect();
//      if(rectF){
//        canvas->setMinimumWidth((int)rectF->right());
//        canvas->setMinimumHeight((int)rectF->bottom());
//      }

      resetClipedDrawRegion(g);

    }
    if((clock()-stime)>100){
      cout<<"drawRegion use time:"<<(clock()-stime)<<endl;
    }
    //cout<<"drawedCount:"<<(drawedCount)<<endl;
    //发送绘制层事件
    spendTime = clock()-stime;
    event(&paintEvent);
  }

  void Layer::drawAll(Gdiplus::Graphics* g){
    drawedCount = 0;
    long stime = clock();
    g->Clear(background);
    const vector<Element*>* allElements = getElements();
    vector<Element*>::const_iterator it = allElements->begin();
    for(; it!=allElements->end(); it++){
      //(*it)->draw(g);
      if((*it)->isVisible() && enableDisplay(*it)){
        drawElement(*it, g);
//        (*it)->draw(g);
//        (*it)->setModified(false);
//        (*it)->setRedraw(false);
        drawedCount++;
      }
    }
    if((clock()-stime)>100){
      cout<<"drawAll use time:"<<(clock()-stime)<<endl;
    }
    //发送绘制层事件
    spendTime = clock()-stime;
    event(&paintEvent);
  }

  /**
   * 画元素
   */
  void Layer::drawElement(Element* e, Gdiplus::Graphics* g){
    e->draw(g);
    throwPaintEvent(e);
    e->setModified(false);
    e->setRedraw(false);

  }

  /**
   * 检查此元素是否在可视区
   */
  bool Layer::enableDisplay(Element* e){
    return true;
  }

  void Layer::unionDrawRegion(const Gdiplus::RectF* rect){
    if(!rect){
      cout<<"unionDrawRegion rect is null"<<endl;
      return;
    }
    if(!clipedRegion){
//      clipedRegion = new Gdiplus::GraphicsPath(Gdiplus::FillModeWinding);
//      clipedRegion->AddRectangle(*rect);
      clipedRegion = new Gdiplus::Region(*rect);
    }else{
      clipedRegion->Union(*rect);
//      clipedRegion->AddRectangle(*rect);
    }
    //clipedRegion->AddRectangle(*rect);

    setModified(true);
  }

  void Layer::destroyDrawRegion(){
    if(clipedRegion){
      //redrawRect = clipedRegion->boundingRect();
      delete clipedRegion;
      clipedRegion = NULL;
    }
  }

  void Layer::clipDrawRegion(Gdiplus::Graphics* g){
    g->SetClip(clipedRegion);
    g->Clear(background);

//    Gdiplus::RectF clipedRect;
//    //clipedRegion->GetBounds(&clipedRect, g);
//    clipedRegion->GetBounds(&clipedRect, NULL, NULL);
//    Gdiplus::SolidBrush brush(Gdiplus::Color(123,122,200,50));
//    g->FillRectangle(&brush, clipedRect);
  }

  void inline Layer::resetClipedDrawRegion(Gdiplus::Graphics* g){
    destroyDrawRegion();
    g->ResetClip();
  }

//  /**
//   * 鼠标离开元素
//   */
//  void Layer::mouseLeaveElement(DLayer::Element* e){
//    ((Element*)e)->mouseLeave();
//    //e->mouseLeave();
//  }
}
